#define __DEBUG

#include "../window/loginwindow.h"

#include "thread.h"
#include <sys/types.h>
#ifndef _WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SOCKET_ERROR -1
#endif
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include "../lib/json/json.h"

void Dlog(const char* mes){
#ifdef __DEBUG
    write(fileno(stdout), mes, strlen(mes));
#endif
}
//安全发送
#define ssend(sid,data,size,i) if(send(sid,data,size,i)==SOCKET_ERROR) return false

int SimpleqqClient::_sid;
int SimpleqqClient::_id;

SimpleqqClient::SimpleqqClient(){
    _sid = 0;

    window_login = new loginWindow();

    window_login->setClient(this);
}

SimpleqqClient::~SimpleqqClient(){
    delete window_login;
}

int SimpleqqClient::init(){
#ifdef _WIN32
    int nRet;
    if((nRet = WSAStartup(MAKEWORD(2,2),&wsaData)) != 0){
        printf("Socket Create Error\n:%d");
        return 0;
    }
#endif
    //初始化socket
    _sid = socket(AF_INET,SOCK_STREAM,0);
    if(_sid == -1){
        return 0;
    }


    //socket数据结构
    sockaddr_in servaddr;

    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    //尝试建立连接
    int res = connect(_sid,(struct sockaddr*)&servaddr, sizeof(servaddr));
    if(res < 0){
        write(fileno(stdout),"连接失败！\n", 15);
        return 0;
    }

    window_login->show();
    return 1;
}


int SimpleqqClient::client_login(void *mes){
    //tests for select model
    bool flag = false;
    int n;
    Json::Value j;
    Json::Reader reader;
    std::string recvs;
    char *recvbuf = (char *)malloc((MAXSIZE+1)*sizeof(char));//对每一个thread都会有一个recvbuf

    loginTMes *Tmes = (loginTMes *)mes;

    Dlog("login...\n");

    //第一步：发送login命令
    if(send(_sid, "login", 5, 0) <= 0 )
        return CS_SENDERROR;
    while(!flag){
        //第二步：服务器返回Acc:id或Rej
        if(1){
            Dlog("try receiving...\n");
            n = recv(_sid, recvbuf, MAXSIZE , 0);
            if(n > 0){
                recvbuf[n] = '\0';
                recvs = recvbuf;

                Dlog("recv from server:");
                Dlog(recvbuf);
                Dlog("\n");

                if(recvs == "Rej")
                    return CS_REJECTED_LOGIN;
                else{
                    recvs = recvs.substr(recvs.find_first_of("Acc:")+4);
                    _id = atoi(recvs.c_str());
                    if(_id < 0)
                        return CS_LOGIN_SERVERERROR;
                }
                flag = true;
            }
        }
    }
        //第三步：服务器已准备接收login信息，发送即可
        //第四步：发送endstream命令，在sendstream中实现

        //json格式
        j["username"] = Tmes->username;
        j["password"] = Tmes->password;
        std::string usermessage = j.toStyledString();

        Dlog("sending login message..\n");
        if(!sendStream(usermessage.c_str(),usermessage.size()))
            return CS_SENDERROR;

        //等待acc/rej
        n = recv(_sid, recvbuf, MAXSIZE, 0);
        if(n > 0){
            recvbuf[n] = '\0';
            recvs = recvbuf;
            Dlog(recvbuf);
        }
        if(recvs == "Rej")
            return CS_LOGIN_USERERROR;


    free(recvbuf);

    return 0;
}

int SimpleqqClient::client_exit(void *mes){
#ifdef _WIN32
    closesocket(_sid);
#else
    close(_sid);
#endif
    mes = 0;
    _sid = 0;
    return 0;
}

int SimpleqqClient::thread_login(std::string &username, std::string &password){
    clientThread *th = new clientThread();
    loginTMes *mes = new loginTMes();

    mes->password = password;
    mes->username = username;

    //设置通知
    QObject::connect(th,SIGNAL(endthread()), th, SLOT(deleteLater()));
    QObject::connect(th,SIGNAL(SignalLogin(int)), window_login, SLOT(loginAcc(int)));
    //设置参数和变量
    th->setmode(CLIENT_LOGIN);
    th->setParam(mes);
    //启动thread
    th->start();
    return 0;
}

/*
 * 方法sendStream(char* data,size)
 * data：发送到服务器的源数据；size：数据的字节数
 * 发送任意长度的数据流，按字节发送
 * 与MAXSIZE比较，大于则分批发送
 * 发送数据格式：id@n:data
 * 结束数据格式：id@endstream:N
 * id:服务器给客户端分配的id
 * n:当前包
 * N:包总数
 *
*/
bool SimpleqqClient::sendStream(const char* data,long size){
    //包装
    std::string resdata="";
    int num = 0;

    resdata += _id + '0';
    resdata += "@";
    resdata += num + '0';
    resdata += ':';

    if(size < MAXSIZE - resdata.size()){
        resdata += data;
        Dlog(resdata.c_str());
        ssend(_sid, resdata.c_str(), resdata.size(), 0);
        ssend(_sid, "endstream:1", 20, 0);
        //发送完毕
    }else{
        //TODO:分包发送
    }
    return true;
}
